package com.tueye.framework.core.template.support;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.util.CollectionUtils;

import com.tueye.utils.TuEyeConstant;

import freemarker.cache.FileTemplateLoader;
import freemarker.cache.MultiTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.SimpleHash;
import freemarker.template.TemplateException;

/**
 * 
 * @author hanxiaowei
 *
 */
@SuppressWarnings("unchecked")
public class FreeMarkerConfiguration {
	
	protected  final Log logger = LogFactory.getLog(getClass());
	
	//模板配置文件资源
	private Resource configLocation;
    //模板设置
	private Properties freemarkerSettings;
    //设置模板共享变量
	private Map freemarkerVariables;
    //默认编码
	private String defaultEncoding="UTF-8";
    //模板加载资源
	private final List templateLoaders = new ArrayList();
    //
	private List preTemplateLoaders;

	private List postTemplateLoaders;
    //模板加载路径
	private String[] templateLoaderPaths;
    //默认资源加载器
	private ResourceLoader resourceLoader = new DefaultResourceLoader();
    //
	private boolean preferFileSystemAccess = true;
	
	public boolean isPreferFileSystemAccess() {
		return preferFileSystemAccess;
	}
	public void setPreferFileSystemAccess(boolean preferFileSystemAccess) {
		this.preferFileSystemAccess = preferFileSystemAccess;
	}
	public Resource getConfigLocation() {
		return configLocation;
	}
	public void setConfigLocation(Resource configLocation) {
		this.configLocation = configLocation;
	}
	public Properties getFreemarkerSettings() {
		return freemarkerSettings;
	}
	public void setFreemarkerSettings(Properties freemarkerSettings) {
		this.freemarkerSettings = freemarkerSettings;
	}
	public Map getFreemarkerVariables() {
		return freemarkerVariables;
	}
	public void setFreemarkerVariables(Map freemarkerVariables) {
		this.freemarkerVariables = freemarkerVariables;
	}
	public String getDefaultEncoding() {
		return defaultEncoding;
	}
	public void setDefaultEncoding(String defaultEncoding) {
		this.defaultEncoding = defaultEncoding;
	}
	public String[] getTemplateLoaderPaths() {
		return templateLoaderPaths;
	}
	public void setTemplateLoaderPaths(String[] templateLoaderPaths) {
		this.templateLoaderPaths = templateLoaderPaths;
	}
	public List getTemplateLoaders() {
		return templateLoaders;
	}
	
	public ResourceLoader getResourceLoader() {
		return resourceLoader;
	}
	public void setResourceLoader(ResourceLoader resourceLoader) {
		this.resourceLoader = resourceLoader;
	}
	public Configuration createConfiguration() throws IOException, TemplateException {
		Configuration config = newConfiguration();
		Properties props = new Properties();

		if (this.configLocation != null) {
			logger.info("Loading FreeMarker configuration from " + this.configLocation);
			PropertiesLoaderUtils.fillProperties(props, this.configLocation);
		}

		if (this.freemarkerSettings != null) {
			props.putAll(this.freemarkerSettings);
		}

		if (!props.isEmpty()) {
			config.setSettings(props);
		}

		if (!CollectionUtils.isEmpty(this.freemarkerVariables)) {
			config.setAllSharedVariables(new SimpleHash(this.freemarkerVariables));
		}

		if (this.defaultEncoding != null) {
			config.setDefaultEncoding(this.defaultEncoding);
		}


		if (this.preTemplateLoaders != null) {
			this.templateLoaders.addAll(this.preTemplateLoaders);
		}

		if (this.templateLoaderPaths != null) {
			for (int i = 0; i < this.templateLoaderPaths.length; i++) {
				this.templateLoaders.add(getTemplateLoaderForPath(this.templateLoaderPaths[i]));
			}
		}
		postProcessTemplateLoaders(this.templateLoaders);

		if (this.postTemplateLoaders != null) {
			this.templateLoaders.addAll(this.postTemplateLoaders);
		}

		TemplateLoader loader = getAggregateTemplateLoader(this.templateLoaders);
		if (loader != null) {
			config.setTemplateLoader(loader);
		}

		postProcessConfiguration(config);
		return config;
	}
	protected Configuration newConfiguration() throws IOException, TemplateException {
		return new Configuration();
	}
	protected TemplateLoader getTemplateLoaderForPath(String templateLoaderPath) {
		if (isPreferFileSystemAccess()) {
			try {
				if(templateLoaderPath.startsWith("/WEB-INF")){
					templateLoaderPath="file:"+TuEyeConstant.getSystemPath()+templateLoaderPath;
				}
				Resource path = getResourceLoader().getResource(templateLoaderPath);
				File file = path.getFile();  
				logger.debug("模板加载路径 [" + path + "] 模板文件绝对路径 [" + file.getAbsolutePath() + "]");
				return new FileTemplateLoader(file);
			}
			catch (IOException ex) {
				logger.error("不能解析模板的加载路径 [" + templateLoaderPath +"] to [java.io.File]: 使用框架的模板加载器", ex);
				return new FrameworkTemplateLoader(getResourceLoader(), templateLoaderPath);
			}
		}
		else {
			return new FrameworkTemplateLoader(getResourceLoader(), templateLoaderPath);
		}
	}


	protected void postProcessTemplateLoaders(List templateLoaders) {
	}


	protected TemplateLoader getAggregateTemplateLoader(List templateLoaders) {
		int loaderCount = templateLoaders.size();
		switch (loaderCount) {
			case 0:
                logger.info("No FreeMarker TemplateLoaders specified");
				return null;
			case 1:
				return (TemplateLoader) templateLoaders.get(0);
			default:
				TemplateLoader[] loaders = (TemplateLoader[]) templateLoaders.toArray(new TemplateLoader[loaderCount]);
			    return new MultiTemplateLoader(loaders);
		}
	}
	protected void postProcessConfiguration(Configuration config) throws IOException, TemplateException {
	}
	
}
